/***********
 *  modem接口
 *
 */
package com.yy.ttmodule.cardStatus;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import android.util.Log;

public class ModemInterface {
    private static final String TAG = "ModemInterface";
    public static final String DEVICE_PATH = "dev/STTYEMS37";
    private List<Command> commands = new ArrayList<Command>();

    private FileReader fr;
    private FileWriter fw;
    private FileOutputStream fos;

    private BufferedReader br;
    private BufferedWriter bw;
    private FileChannel dev_fc_out;
    private BmService mService;
    private CommandWriter mWriter;

    public ModemInterface(BmService service) {
        this.mService = service;

        openDevice();

        mWriter = new CommandWriter();
        mWriter.start();

        //鍏抽棴涓诲姩涓婃姤
        closeUnsolicited();
    }

    private boolean recheckDevices() {
        int i = 10;
        while (!checkDevices() && (i-- > 0)) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            openDevice();
        }
        if (i <= 0) {
            Log.i(TAG, "Devices can't open!!!");
            return false;
        }
        return true;
    }

    private boolean checkDevices() {
        if (null == fr) {
            return false;
        }
        if (null == fw) {
            return false;
        }
        if (null == fos) {
            return false;
        }
        if (null == br) {
            return false;
        }
        if (null == bw) {
            return false;
        }
        if (null == dev_fc_out) {
            return false;
        }
        return true;
    }

    private void openDevice() {
        closeDevice();

        try {
            fr = new FileReader(DEVICE_PATH);
            fw = new FileWriter(DEVICE_PATH);
            fos = new FileOutputStream(DEVICE_PATH);

            br = new BufferedReader(fr);
            bw = new BufferedWriter(fw);
            dev_fc_out = fos.getChannel();

            closeUnsolicited();
            Log.i(TAG, DEVICE_PATH + " open OK!!!");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "open " + DEVICE_PATH + " Error!!!!");
            e.printStackTrace();
            closeDevice();
        }
    }

    private void closeFosChannel() {
        try {
            if (null != dev_fc_out) {
                dev_fc_out.close();
                dev_fc_out = null;
                Log.i(TAG, DEVICE_PATH + " closed!");
            }
        } catch (Exception e) {
            Log.e(TAG, "dev_fc_out error!!!");
            e.printStackTrace();
        }
    }

    private void closeBufferedWriter() {
        try {
            if (null != bw) {
                bw.close();
                bw = null;
            }
        } catch (Exception e) {
            Log.e(TAG, "bw Error!!!");
        }
    }

    private void closeBufferedReader() {
        try {
            if (null != br) {
                br.close();
                br = null;
            }
        } catch (Exception e) {
            Log.e(TAG, "br Error!!!");
        }
    }

    private void closeFos() {
        try {
            if (null != fos) {
                fos.close();
                fos = null;
            }
        } catch (Exception e) {
            Log.e(TAG, "fos Error!!!");
        }
    }

    private void closeFileWriter() {
        try {
            if (null != fw) {
                fw.close();
                fw = null;
            }
        } catch (Exception e) {
        }
    }

    private void closeFileReader() {
        try {
            if (null != fr) {
                fr.close();
                fr = null;
            }
        } catch (Exception e) {
        }
    }

    private void closeDevice() {
        closeFosChannel();
        closeBufferedWriter();
        closeBufferedReader();
        closeFos();
        closeFileWriter();
        closeFileReader();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //添加命令到列表
    public void addCommandToWriteList(Command command) {
        if (command != null) {
            synchronized (commands) {
                commands.add(command);
            }
        }
    }

    private void addCloseUnsolicitedCmdToWriteList(Command command) {
        if (command != null) {
            synchronized (commands) {
                commands.add(0, command);
            }
        }
    }

    public class CommandWriter extends Thread {
        private Command currentCommand = null;

        @Override
        public void run() {
            for (; ; ) {
                int size = commands.size();
                while (size == 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    synchronized (commands) {
                        size = commands.size();
                    }
                }

                if (!recheckDevices()) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    continue;
                }
                //濡傛灉褰撳墠鍛戒护涓虹┖鍒欎粠鍛戒护鍒楄〃涓彇绗竴涓懡浠よ繘琛屽彂閫�
                if (currentCommand == null) {
                    currentCommand = commands.get(0);
                }

                Log.i(TAG, "currentCommand = " + currentCommand);
                if (writeCmdToModem(currentCommand)) {//写命令到modem
                    String result = readResponse();//读取响应消息
                    // for test
                    Log.i(TAG, "response=" + result);
                    currentCommand.setResponse(result);
                    sendResponse(currentCommand);
                    synchronized (commands) {
                        commands.remove(currentCommand);
                    }
                    currentCommand = null;
                } else {//失败后，重新openDevices时，会插入closeUnsolicited
                    currentCommand = null;
                }
            }
        }
    }

    /**
     * 鍙戦�佸懡浠ゆ墽琛岀粨鏋滅粰Worker
     *
     *///
    private void sendResponse(Command command) {
        if (command == null) {
            return;
        }
        int workerId = command.getWorkerId();
        if (workerId < 0) {
            Log.d(TAG, "no worker need receive this response!");
            return;
        }
        //通过socket发送命令,及其响应
        //鍙戦�佺粰Sokect缁勪欢杩涜澶勭悊
        mService.getSocketInterface().sendResponse(command);
    }

    /**
     * 鍐欏懡浠ゅ埌Modem
     *
     * @param command
     * @return
     *///写命令到modem
    private boolean writeCmdToModem(Command command) {
        if ((command == null) || (command.getMsgString() == null) || (dev_fc_out == null)) {
            Log.d(TAG, "WriteCmdToModem--->parm wrong!");
            return true;
        }
        Log.d(TAG, "WriteCmdToModem -->" + command.toString());
        try {
            dev_fc_out.write(ByteBuffer.wrap(command.getMsgString().getBytes()));
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "!!!WriteCmdToModem write Error!!!");
            closeDevice();
            return false;
        }
        Log.d(TAG, "WriteCmdToModem success");
        return true;
    }

    public static final long DURATION_TIMES = 25 * 1000;

    //下发数据出现多余（ 这个函数有问题，会阻塞）
    private void readLeftData() {
        Log.i(TAG, "readLeftData start");
        try {
/*            while(br.ready()){
                String line = br.readLine();
                Log.e(TAG, "Left Data: line = " + line);
            }*/
            for (int i=5; i>0; i--){
                br.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        Log.i(TAG, "readLeftData end");
    }

    /**
     * 璇诲彇鍛戒护鎵ц缁撴灉
     *
     * @return
     *///
    private String readResponse() {
        // TODO Auto-generated method stub

        long expired_time = System.currentTimeMillis() + DURATION_TIMES;
        StringBuilder response = new StringBuilder();
        String line = null;
        if (br == null) {
            Log.d(TAG, "readResponse br null!");
            return null;
        }
        long time = System.currentTimeMillis();
        do {//在指定超时时间内,读取响应
            try {
                Log.d(TAG, "readResponse read line!");
                line = br.readLine();
                Log.d(TAG, "readResponse line = " + line);
                if (line == null || line.equals("")) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else if (line.equals("ok") || line.equals("OK") || line.startsWith("+CME ERROR:")
                        || line.contains("ERROR")) {
                    response.append(line);
                    break;
                } else {
                    response.append(line);
                    response.append(",");
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                Log.e(TAG, "!!!readResponse Error!!!");
                closeDevice();
            }
            time = System.currentTimeMillis();
        } while (time < expired_time); //瓒呮椂鍚庨��鍑�

        Log.d(TAG, "response = " + response.toString());

        return response.toString();
    }

    /**
     * 鍏抽棴涓诲姩涓婃姤
     *///关闭自动上报
    private void closeUnsolicited() {//此消息不需要接收响应
        //this command needn't receive response
        Command command = new Command(-1, -1, "at^dlks=0\r\n");
        addCloseUnsolicitedCmdToWriteList(command);
    }

}
